package com.alibaba.citrus.ots.common.log;

import com.alibaba.citrus.ots.common.annotation.FieldColMapping;
import com.alibaba.citrus.ots.common.annotation.OperaterLog;
import com.alibaba.cz.base.tool.log.Log;
import com.alibaba.cz.base.tool.log.model.OpLogModel;
import com.alibaba.cz.base.tool.log.model.OperateType;
import com.alibaba.cz.base.tool.log.model.OperatorType;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;

/**
 * @author: qiaojiange
 * @create: 2021/11/14
 * @Description 操作日志处理器
 */
@Aspect
@Component
@Order(1)
public class OperaterLogHandler {
    private static Log log = Log.getLogger(OperaterLogHandler.class);


    @Pointcut("@annotation(com.alibaba.citrus.ots.common.annotation.OperaterLog)")
    private void cutMethod() {
    }

    @Around("cutMethod()")
    public Object doAroundAdvice(ProceedingJoinPoint point) throws Throwable {
        OperaterLog operaterLog = AopUtils.getTargetMethodAnnotation(point, OperaterLog.class);
        if (operaterLog == null) {
            return null;
        }

        OperateType operateType = operaterLog.operateType();
        OperatorType operatorType = operaterLog.operatorType();
        ParamTypeEnum paramTypeEnum = operaterLog.choiceParam();
        ModuleEnum module = operaterLog.module();

        Object result = point.proceed();

        //获取参数注解
        MethodSignature methodSignature = (MethodSignature) point.getSignature();
        Annotation[][] parameterAnnotations = methodSignature.getMethod().getParameterAnnotations();

        String fieldName = "";
        String fieldValue = "";
        boolean isContinue = true;
        //第一层是遍历参数
        for (int i = 0; i < parameterAnnotations.length; i++) {
            if (!isContinue) {
                break;
            }

            for (int j = 0; j < parameterAnnotations[i].length; j++) {
                Annotation annotation = parameterAnnotations[i][j];
                if (annotation instanceof FieldColMapping) {
                    FieldColMapping fieldColMappingAnnotation = (FieldColMapping) annotation;
                    fieldName = fieldColMappingAnnotation.fieldName();
                    fieldValue = fieldColMappingAnnotation.fieldValue();
                    //如果字段值不为空，直接返回
                    if (StringUtils.isNotBlank(fieldValue)) {
                        isContinue = false;
                        break;
                    }

                    //如果是出参的，获取出参上的字段值
                    if (ParamTypeEnum.OUTPUT_PARAM.equals(paramTypeEnum)) {
                        //如果等于出参
                        Class returnType = methodSignature.getReturnType();
                        Field field = returnType.getDeclaredField(fieldName);
                        field.setAccessible(true);
                        Object o = field.get(result);
                        fieldValue = field.get(result).toString();
                    } else if (ParamTypeEnum.INPUT_PARAM.equals(paramTypeEnum)) {
                        //获取参数对象
                        Object object = point.getArgs()[i];
                        //获取参数的clazz
                        Class clazz = methodSignature.getParameterTypes()[i];
                        Field field = clazz.getDeclaredField(fieldName);
                        field.setAccessible(true);
                        fieldValue = field.get(object).toString();
                    }
                    isContinue = false;
                    break;
                }
            }
        }

        OpLogModel<String> model = OpLogModel.<String>builder().operatorType(operatorType.getOperatorType())
                .operatorType(operatorType.getOperatorType())
                .operateType(operateType.getOperateType())
                .objectId(fieldValue)
                .fieldName(fieldName)
                .moduleId(module.getModuleId())
                .moduleName(module.getModuleName()).build();
        log.asyncMonitorObjectChangeV2(model);
        return result;
    }

}
